package com.ocean.web.util;

import com.ocean.metadata.domain.OMetadata;
import com.ocean.metadata.service.IOMetadataService;
import com.ocean.system.domain.OFileMetadata;
import org.springframework.beans.factory.annotation.Autowired;
import ucar.ma2.*;
import ucar.nc2.*;

import java.io.IOException;
import java.util.*;

public class CpjypgGRAPES {
    // 目标经纬度范围中国近海
    private static final double MIN_LAT = 14.0;   // 14°N
    private static final double MAX_LAT = 42.0;   // 42°N
    private static final double MIN_LON = 105.0;  // 105°E
    private static final double MAX_LON = 132.0;  // 132°E

    /**
     * 测试裁剪4个变量（UGRD/VGRD/PRMSL/GUST），生成单个NC文件
     * @param args
     */
    public static void main(String[] args) throws IOException {
        // 原文件路径和新文件路径（替换为实际路径）
        String inputPath = "E:\\项目资料备份\\新云平台文件\\2025工作\\样例数据-检验\\GRAPES全球大气数值预报\\CMA_BEN_GRAPESGFS_GLDT_2025102800_240h_SSW.nc";
        String outputPath = "E:\\CMA_BEN_GRAPESGFS_GLDT_2025102800_240h_SSW_cropped.nc";
        CJNcdatazgjh(inputPath, outputPath);
    }

    /**
     * 裁剪4个变量（UGRD/VGRD/PRMSL/GUST），生成单个NC文件
     */
    public static boolean CJNcdatazgjh(String inputPath, String outputPath) throws IOException {
        Map<String,String> filedata = new HashMap<>();
        NetcdfFile inputFile = null;
        NetcdfFileWriter writer = null;
        try {
            // 1. 打开原NC文件
            inputFile = NetcdfFile.open(inputPath);
            System.out.println("成功打开原文件: " + inputPath);

            // 2. 获取所有必需变量（经纬度/时间为double，4个目标变量为float）
            Variable latVar = inputFile.findVariable("latitude");    // 纬度（double）
            Variable lonVar = inputFile.findVariable("longitude");   // 经度（double）
            Variable timeVar = inputFile.findVariable("time");       // 时间（double）
            // 4个目标变量（float类型）
            Variable ugrdVar = inputFile.findVariable("UGRD_10maboveground");
            Variable vgrdVar = inputFile.findVariable("VGRD_10maboveground");
            Variable prmslVar = inputFile.findVariable("PRMSL_meansealevel");
            Variable gustVar = inputFile.findVariable("GUST_10maboveground");

            // 校验变量存在性
            if (latVar == null || lonVar == null || timeVar == null) {
                throw new RuntimeException("经纬度或时间变量不存在，请检查变量名");
            }
            if (ugrdVar == null || vgrdVar == null || prmslVar == null || gustVar == null) {
                throw new RuntimeException("4个目标变量（UGRD/VGRD/PRMSL/GUST）未全部找到，请检查变量名");
            }

            // 校验数据类型
            if (latVar.getDataType() != DataType.DOUBLE || lonVar.getDataType() != DataType.DOUBLE || timeVar.getDataType() != DataType.DOUBLE) {
                throw new RuntimeException("经纬度或时间变量不是double类型，请检查文件");
            }
            if (ugrdVar.getDataType() != DataType.FLOAT || vgrdVar.getDataType() != DataType.FLOAT ||
                    prmslVar.getDataType() != DataType.FLOAT || gustVar.getDataType() != DataType.FLOAT) {
                throw new RuntimeException("目标变量不是float类型，请检查文件");
            }

            // 3. 读取经纬度数据（double类型）
            double[] lats = readDoubleArray(latVar);
            double[] lons = readDoubleArray(lonVar);
            int timeSize = timeVar.getShape()[0];  // 时间维度大小（81）

            // 4. 计算裁剪索引（适配经纬度升序/降序）
            int[] latIndices = getRangeIndices(lats, MIN_LAT, MAX_LAT);
            int[] lonIndices = getRangeIndices(lons, MIN_LON, MAX_LON);

            if (latIndices == null || lonIndices == null) {
                throw new RuntimeException("目标范围超出原数据范围");
            }
            int latStart = latIndices[0], latCount = latIndices[1];
            int lonStart = lonIndices[0], lonCount = lonIndices[1];
            System.out.printf("裁剪范围：纬度[%d:%d]，经度[%d:%d]，时间维度[%d]%n",
                    latStart, latStart + latCount - 1, lonStart, lonStart + lonCount - 1, timeSize);

            // 5. 裁剪经纬度和时间数据
            Array croppedLat = cropVariable(latVar, new int[]{latStart}, new int[]{latCount});
            Array croppedLon = cropVariable(lonVar, new int[]{lonStart}, new int[]{lonCount});
            Array timeData = timeVar.read();  // 时间维度全取

            // 6. 统一裁剪4个目标变量（维度：time, lat, lon）
            int[] varOrigin = new int[]{0, latStart, lonStart};  // 时间从0开始，裁剪经纬度
            int[] varShape = new int[]{timeSize, latCount, lonCount};
            Array croppedUgrd = cropVariable(ugrdVar, varOrigin, varShape);
            Array croppedVgrd = cropVariable(vgrdVar, varOrigin, varShape);
            Array croppedPrmsl = cropVariable(prmslVar, varOrigin, varShape);
            Array croppedGust = cropVariable(gustVar, varOrigin, varShape);

            // 7. 创建新NC文件，写入所有数据
            writer = NetcdfFileWriter.createNew(NetcdfFileWriter.Version.netcdf4, outputPath);
            createNewNCFile(writer, inputFile,
                    latVar, lonVar, timeVar, ugrdVar, vgrdVar, prmslVar, gustVar,
                    croppedLat, croppedLon, timeData,
                    croppedUgrd, croppedVgrd, croppedPrmsl, croppedGust,
                    latCount, lonCount, timeSize);

            System.out.println("新文件生成成功: " + outputPath);
        return true;
        } catch (IOException | InvalidRangeException e) {
            e.printStackTrace();
            return false;
        } finally {
            // 关闭资源，避免文件占用
            if (inputFile != null) {
                try { inputFile.close(); } catch (IOException e) { e.printStackTrace(); }
            }
            if (writer != null) {
                try { writer.close(); } catch (IOException e) { e.printStackTrace(); }
            }
        }
    }

    /**
     * 读取double类型数组（适配经纬度/时间变量）
     */
    private static double[] readDoubleArray(Variable var) throws IOException {
        Array array = var.read();
        return (double[]) array.copyTo1DJavaArray();
    }

    /**
     * 计算double数组中目标范围的起始索引和长度
     */
    private static int[] getRangeIndices(double[] array, double min, double max) {
        int start = -1, end = -1;
        boolean isAscending = array.length > 1 && array[array.length - 1] > array[0];

        for (int i = 0; i < array.length; i++) {
            double val = array[i];
            if ((isAscending && val >= min && val <= max) || (!isAscending && val <= min && val >= max)) {
                if (start == -1) start = i;
                end = i;
            }
        }

        if (start == -1 || end == -1) return null;
        return new int[]{start, end - start + 1};
    }

    /**
     * 通用变量裁剪方法（保留原数据类型）
     */
    private static Array cropVariable(Variable var, int[] origin, int[] shape) throws IOException, InvalidRangeException {
        Range[] ranges = new Range[origin.length];
        for (int i = 0; i < origin.length; i++) {
            ranges[i] = new Range(origin[i], origin[i] + shape[i] - 1);
        }
        return var.read(Arrays.asList(ranges));
    }

    /**
     * 创建新NC文件，写入4个裁剪后的变量
     */
    private static void createNewNCFile(NetcdfFileWriter writer, NetcdfFile inputFile,
                                        Variable latVar, Variable lonVar, Variable timeVar,
                                        Variable ugrdVar, Variable vgrdVar, Variable prmslVar, Variable gustVar,
                                        Array croppedLat, Array croppedLon, Array timeData,
                                        Array croppedUgrd, Array croppedVgrd, Array croppedPrmsl, Array croppedGust,
                                        int newLatSize, int newLonSize, int timeSize) throws IOException, InvalidRangeException {

        // 1. 定义维度（保留原名称）
        Dimension timeDim = writer.addDimension(null, timeVar.getDimensions().get(0).getName(), timeSize);
        Dimension latDim = writer.addDimension(null, latVar.getDimensions().get(0).getName(), newLatSize);
        Dimension lonDim = writer.addDimension(null, lonVar.getDimensions().get(0).getName(), newLonSize);
        List<Dimension> varDims = List.of(timeDim, latDim, lonDim);  // 4个变量的共同维度

        // 2. 创建变量（保留原数据类型和属性）
        // 经纬度+时间（double）
        Variable newLatVar = writer.addVariable(null, latVar.getShortName(), DataType.DOUBLE, latDim.getName());
        copyVariableAttributes(latVar, newLatVar);
        Variable newLonVar = writer.addVariable(null, lonVar.getShortName(), DataType.DOUBLE, lonDim.getName());
        copyVariableAttributes(lonVar, newLonVar);
        Variable newTimeVar = writer.addVariable(null, timeVar.getShortName(), DataType.DOUBLE, timeDim.getName());
        copyVariableAttributes(timeVar, newTimeVar);

        // 4个目标变量（float）
        Variable newUgrdVar = writer.addVariable(null, ugrdVar.getShortName(), DataType.FLOAT, varDims);
        copyVariableAttributes(ugrdVar, newUgrdVar);
        Variable newVgrdVar = writer.addVariable(null, vgrdVar.getShortName(), DataType.FLOAT, varDims);
        copyVariableAttributes(vgrdVar, newVgrdVar);
        Variable newPrmslVar = writer.addVariable(null, prmslVar.getShortName(), DataType.FLOAT, varDims);
        copyVariableAttributes(prmslVar, newPrmslVar);
        Variable newGustVar = writer.addVariable(null, gustVar.getShortName(), DataType.FLOAT, varDims);
        copyVariableAttributes(gustVar, newGustVar);

        // 3. 复制全局属性
        for (Attribute attr : inputFile.getGlobalAttributes()) {
            writer.addGlobalAttribute(attr);
        }

        // 4. 写入所有数据
        writer.create();
        writer.write(newLatVar, croppedLat);
        writer.write(newLonVar, croppedLon);
        writer.write(newTimeVar, timeData);
        writer.write(newUgrdVar, croppedUgrd);
        writer.write(newVgrdVar, croppedVgrd);
        writer.write(newPrmslVar, croppedPrmsl);
        writer.write(newGustVar, croppedGust);
    }

    /**
     * 复制变量属性（保留单位、填充值等元数据）
     */
    private static void copyVariableAttributes(Variable src, Variable dest) {
        for (Attribute attr : src.getAttributes()) {
            dest.addAttribute(attr);
        }
    }
}